<template>
    <div class="main">
        <!-- 语言切换 -->
        <div class="login-language" v-if="isI18nLang == 'YES'" @mouseenter="show = true" @mouseleave="show = false">
            <div style="position: relative">
                <div class="login-language-head">
                    <my-icon type="iconearth-full" style="margin-right: 5px"></my-icon> {{ i18nTitle }}<my-icon
                        type="iconicon-test49" style="margin-left: 5px"></my-icon>
                </div>
                <div class="login-language-common" v-if="show">
                    <div class="login-language-common-list" v-for="item in i18nList" :key="item.type">
                        <div @click="setI18nType(item.type)" class="login-language-common-list-le">{{ item.name }}</div>
                        <my-icon v-if="i18nTitle == item.name" type="iconicon"></my-icon>
                    </div>
                </div>
            </div>
        </div>
        <a-form id="formLogin" class="user-layout-login" ref="formLogin" :form="form" @submit="handleSubmit">
            <div class="hermg"><img :src="loginPageLogoUrl"></div>
            <div align="center" class="jpaas">
                <span>{{ $i18(loginPageTitle) }}</span>
            </div>
            <div class="jpaasbutton">
                <a-form-item>
                    <a-input size="large" type="text" :placeholder="$ti18('login.usernameWarning', '输入账号提示')"
                        v-decorator="['username',
                            { rules: [{ required: true, message: $ti18('login.usernameWarning', '输入账号提示') }, { validator: handleUsernameOrEmail }], validateTrigger: 'change' }]">
                        <a-icon slot="prefix" type="user" :style="{ color: 'rgba(0,0,0,.25)' }" />
                    </a-input>
                </a-form-item>
                <a-form-item>
                    <a-input size="large" type="password" autocomplete="false"
                        :placeholder="$ti18('login.passwordWarning', '输入密码提示')" @enter="handleSubmit"
                        v-decorator="['password', { rules: [{ required: true, message: $ti18('login.passwordWarning', '输入密码提示') }], validateTrigger: 'blur' }]">
                        <a-icon slot="prefix" type="lock" :style="{ color: 'rgba(0,0,0,.25)' }" />
                    </a-input>
                </a-form-item>
                <a-row :gutter="8" style="width: 100%" v-if="ignoreValidCode != 'true'">
                    <a-col class="gutter-row" :span="16">
                        <a-form-item>
                            <a-input size="large" type="text"
                                :placeholder="$ti18('login.validCode', '请输入验证码', '', 'input')" @enter="handleSubmit"
                                v-decorator="['validCode', { rules: [{ required: true, message: $ti18('login.validCode', '请输入验证码', '', 'input') }], validateTrigger: 'blur' }]">
                                <a-icon slot="prefix" type="mail" :style="{ color: 'rgba(0,0,0,.25)' }" />
                            </a-input>
                        </a-form-item>
                    </a-col>
                    <a-col class="gutter-row" :span="8">
                        <img class="getCaptcha" :src="codesrc" @click="getImgCode">
                    </a-col>
                </a-row>


                <a-form-item style="width:100%;">
                    <a-button size="large" type="primary" htmlType="submit" class="login-button"
                        :loading="state.loginBtn" :disabled="state.loginBtn">{{ $ti18('login.login', '登录') }}
                    </a-button>
                </a-form-item>
                <div style="display: flex;justify-content: space-between;">
                    <!--                    <div>-->
                    <!--                        {{$ti18('login.notregistered','新企业?')}}<a target="_blank" href="http://www.redxun.cn/jsaas/cus_reg.jsp">{{$ti18('login.freeLogon','免费试用')}}</a>-->
                    <!--                    </div>-->
                    <div>
                        <!--                        <router-link :to="{ name: 'forget'}" class="forge-password">
                            {{$ti18('login.forgotPwd','忘记密码')}}
                        </router-link>-->
                    </div>
                </div>
                <template v-if="isShowOtherLogin">
                    <a-divider :plain="true">{{ $ti18('login.otherLogin', '其它登录方式') }}</a-divider>
                    <div class="footerIconBox">
                        <template v-for="item of platformIcon">
                            <div :class="['iconItem', item.cls]" @click="qrcodeLogin(item.id)" :title="item.name"
                                :key="item.cls">
                            </div>
                        </template>
                    </div>
                </template>

            </div>
        </a-form>
    </div>
</template>

<script>
import { mapActions } from 'vuex'
import { timeFix } from '@/utils/util'
import uuid from '@/utils/uuid'
import { ACCESS_TOKEN } from '@/store/mutation-types'
import { mapState, mapMutations } from 'vuex'
import LoginApi from '@/api/login'
import { JSEncrypt } from 'jsencrypt';
import compomentLang from '../../locales/lang/impl/layouts/compomentLang';
import { sm2 } from 'sm-crypto';

export default {
    name: 'Login',


    data() {
        return {
            platformIcon: [],
            defaultPlatformIcon: [
                { name: this.$ti18('login.WeChatGzh', '微信公众号'), id: 1, cls: 'WeChatGzh' },
                { name: this.$ti18('login.qiyeweixin', '企业微信'), id: 6, cls: 'WeChat' },
                { name: this.$ti18('login.dingding', '钉钉'), id: 5, cls: 'dingding' },
                { name: this.$ti18('login.feishu', '飞书'), id: 4, cls: 'feishu' }
            ],
            //图片的地址
            codesrc: "",
            //登录生成的随机ID,用于生成图片
            deviceId: "",

            isLoginError: false,

            form: this.$form.createForm(this),

            //是否忽略验证码
            ignoreValidCode: 'true',
            //跳转URL
            redirect: "",
            //登录页标题
            loginPageTitle: '',
            //登录页版权
            loginPageCopyright: '',
            //默认logo
            loginPageLogoUrl: process.env.BASE_URL + 'image/log.png',
            //密码模式
            passwordmode: "default",

            state: {
                loginBtn: false,
                loginType: 0,
            },
            passwordPublicKey: "",
            i18nDefault: process.env.VUE_APP_LANGUAGE,
            i18nTitle: "中文",
            i18nType: "",
            i18nList: [],
            isI18nLang: process.env.VUE_APP_ISLANGUAGE,
            show: false,
            //国产sm2公钥
            sw2PublicKey: process.env.VUE_APP_SM2_PUBLIC_KEY,
            //租户信息
            sitettingJson: {},
            //是否租户登录
            isTenantLogin: false,
            tenantId: "",
            //域名值
            hostName: ""
        }
    },
    created() {
        let route = this.$route;
        //记录跳转回日志。
        if (route.query.redirect) {
            this.redirect = route.query.redirect;
        }
        this.getTenantByUrl();
        this.getImgCode();
        this.casLogin();
        this.setLogined(false);
    },
    mounted() {
        this.getLoginConfig();
    },
    computed: {
        ...mapState({
            navigation: state => state.appSetting.navigation,
        }),
        isShowOtherLogin() {
            return this.platformIcon && this.platformIcon.length > 0;
        }
    },
    methods: {
        ...mapActions({
            Login: 'user/Login',
            AuthorizeLogin: 'user/AuthorizeLogin',
            AuthorizeTicketLogin: 'user/AuthorizeTicketLogin',
            Logout: 'user/Logout',
            setLogined: 'appSetting/setLogined',
        }),
        ...mapMutations('appSetting', ['setNavigation', 'setActiveKey', 'clearAppKey', 'clearActiveKey',
            'setPasswordmode', 'setSiteName', 'clearNavigation', 'setFrontType', 'setAppMode']),
        // name 是你要获取的那个参数的字段 比如 code=我是谁 name 就是 code
        getQueryString(name) {
            var reg = new RegExp('(^|&)' + name + '=([^&]*)(&|$)', 'i')
            var r = decodeURIComponent(window.location.search).substr(1).match(reg)
            if (r !== null) return r[2]
            return null
        },
        initI18n() {
            let language = window.localStorage.getItem("language");
            if (!language) {
                this.setI18nType(this.i18nDefault);
                return;
            }
            this.setI18nType(language);
        },
        setI18nType(type) {
            this.i18nType = type;
            this.$i18n.locale = type;
            let obj = this.i18nList.find(row => {
                return type == row.type;
            });
            if (obj) {
                this.i18nTitle = obj.name;
            }
            window.localStorage.setItem("language", type);
        },
        i18n(name, text, key) {
            return this.$ti18(name, text, "viewsUser", key);
        },
        getConfig(config) {
            if (!config) { return {} }
            return new Function(`return ${config}`)()
        },
        //获取登录相关的配置参数
        getLoginConfig() {
            let self = this;
            LoginApi.getLoginConfig(this.hostName).then((res) => {
                let result = res.data;
                self.initTenantInfo(result);

                //密码加密模式
                self.setPasswordmode(result.passwordmode);
                self.passwordmode = result.passwordmode;
                self.passwordPublicKey = result.passwordPublicKey;
                //多语言。
                self.i18nList = result.multiLinguals;
                window.localStorage.setItem("i18nList", JSON.stringify(result.multiLinguals));
                self.initI18n();
                //服务类型。
                self.setAppMode(result.appMode);

                // 获取已配置的平台列表
                let platformList = result.platformList;
                if (platformList && platformList.length > 0) {
                    self.platformIcon = self.defaultPlatformIcon.filter(platform => platformList.contains(platform.cls));
                }

            });
        },
        initTenantInfo(result) {
            //isTenantLogin
            let self = this;
            if (result.sitettingJson) {
                if (result.sitettingJson.tenantId && result.sitettingJson.tenantId != "1") {
                    self.tenantId = result.sitettingJson.tenantId;
                    self.isTenantLogin = true;
                }

                self.sitettingJson = JSON.parse(result.sitettingJson.confs);

                self.ignoreValidCode = self.sitettingJson.ignoreValidCode;

                if (self.sitettingJson.loginPageConfig) {
                    var loginPageConfig = self.sitettingJson.loginPageConfig;
                    self.loginPageTitle = self.getConfig(loginPageConfig.loginPageTitle)
                    self.loginPageCopyright = self.$i18(self.getConfig(loginPageConfig.loginPageCopyright))
                    //设置标题
                    self.setSiteName(self.getConfig(self.sitettingJson.homePageTitle));
                    document.title = self.$i18(self.loginPageTitle, "登录页标题国际化")
                    localStorage.setItem("siteName", JSON.stringify(self.getConfig(self.sitettingJson.homePageTitle)));
                    if (loginPageConfig.loginPageLogo) {
                        self.loginPageLogoUrl = self.getFilePath(loginPageConfig.loginPageLogo);
                    }
                }
                localStorage.setItem("linkLogoUrl", self.sitettingJson.linkLogoUrl);
            } else {
                //是否显示验证码
                self.ignoreValidCode = result.ignoreValidCode;
                if (result.loginPageConfig) {
                    var loginPageConfig = self.getConfig(result.loginPageConfig);
                    self.loginPageTitle = self.getConfig(loginPageConfig.loginPageTitle)
                    self.loginPageCopyright = self.$i18(self.getConfig(loginPageConfig.loginPageCopyright))
                    //设置标题
                    self.setSiteName(self.getConfig(result.homePageTitle));
                    document.title = self.$i18(self.loginPageTitle, "登录页标题国际化")
                    localStorage.setItem("siteName", JSON.stringify(self.getConfig(result.homePageTitle)));
                    if (loginPageConfig.loginPageLogo) {
                        self.loginPageLogoUrl = self.getFilePath(loginPageConfig.loginPageLogo);
                    }
                }
                localStorage.setItem("linkLogoUrl", self.sitettingJson.linkLogoUrl || "");
            }
        },
        getTenantByUrl() {
            this.hostName = window.location.hostname;
        },
        getJsEncryptPassword(password) {
            // 新建JSEncrypt对象
            let encryptor = new JSEncrypt();
            // 设置公钥
            //encryptor.setPublicKey(publicKey);
            encryptor.setPublicKey(this.passwordPublicKey);
            var jm_data = encryptor.encrypt(password);
            // 加密数据
            return jm_data;
        },
        //集成cas
        casLogin() {
            var basePath = process.env.VUE_APP_ADMIN_FRONT;
            //储存 portalUrl 用在jpaas-portal门户 里面用;
            window.localStorage.setItem('portalUrl', basePath);
            if (this.getQueryString('token') != null) {
                var token = decodeURIComponent(this.getQueryString('token'));
                Vue.ls.set(ACCESS_TOKEN, token, 12 * 60 * 60 * 1000)
                this.$store.commit('SET_TOKEN', token)

                this.$router.push({ name: 'index' }, () => {
                    this.$notification.success({
                        message: this.i18n('tips.welcome', '欢迎'),
                        description: `${timeFix()}，` + this.i18n('tips.welcomeBack', '欢迎回来!')
                    })
                });

                this.isLoginError = false
            }
            /**
             * cas检测是否存在ticket
             */
            var ticket = this.getDecodeURIQueryString('ticket');
            //登录成功后回调
            if (ticket) {
                this.logTicketLogin(ticket);
                return;
            }
        },
        logTicketLogin(ticket) {
            const {
                form: { validateFields },
                state,
                AuthorizeTicketLogin
            } = this;
            state.loginBtn = true;
            const loginParams = {
                ticket: ticket
            };
            AuthorizeTicketLogin(loginParams)
                .then((res) => this.loginSuccess(res))
                .catch(err => this.requestFailed(err))
                .finally(() => {
                    state.loginBtn = false
                });
        },
        getDecodeURIQueryString(variable) {
            var newUrl = decodeURIComponent(window.location.search);
            if (newUrl.indexOf("/?") > -1) {
                var urlList = newUrl.split("/?");
                newUrl = urlList[1];
            }
            var param = newUrl;
            if (param.indexOf("&") > -1) {
                var list = param.split("&");
                for (var i = 0; i < list.length; i++) {
                    var obj = list[i];
                    if (obj.indexOf(variable) > -1) {
                        var returnList = obj.split("=");
                        return returnList[1];
                    }
                }
            } else {
                if (param.indexOf(variable) > -1) {
                    var returnList = param.split("=");
                    return returnList[1];
                }
            }
            return null;
        },
        //验证用户名邮件合法性
        handleUsernameOrEmail(rule, value, callback) {
            const { state } = this
            const regex = /^([a-zA-Z0-9_-])+@([a-zA-Z0-9_-])+((\.[a-zA-Z0-9_-]{2,3}){1,2})$/
            if (regex.test(value)) {
                state.loginType = 0
            } else {
                state.loginType = 1
            }
            callback()
        },
        getHomeArrTitle() {
            let lang = compomentLang.compomentLang.navigationBar.homePage;
            return JSON.stringify(lang);
        },
        sm2Encrypt(password) {
            const sm2 = require('sm-crypto').sm2
            let pwd = sm2.doEncrypt(password, this.sw2PublicKey);
            return pwd.toString();
            /*let keypair = sm2.generateKeyPairHex();
            // 公钥
            let publicKey = keypair.publicKey.toUpperCase();
            // 私钥
            let privateKey = keypair.privateKey.toUpperCase();*/
        },
        checkUserName(username) {
            let res = {
                status: true,
                userName: ""
            }
            if (!username || !username.trim()) {
                return res;
            }

            let tenantName = username.trim();
            if (!this.isTenantLogin) {
                res.userName = tenantName;
                return res;
            }

            if (tenantName.indexOf("@") > -1) {
                let names = tenantName.split("@");
                if (!names[0]) {
                    this.$message.error("登录名@字符串前的登录名不能为空!");
                    res.status = false;
                    return res;
                } else if (!names[1]) {
                    res.userName = names[0] + "@" + this.hostName;
                    return res;
                } else if (names[1] != this.hostName) {
                    this.$message.error("@" + this.$ti18('login.messageInfo.notHostName', '后面的字符串不等于域名') + "【" + this.hostName + "】!");
                    res.status = false;
                    return res;
                }
                res.userName = tenantName;
                return res;
            } else {
                if (this.isTenantLogin) {
                    res.userName = tenantName + "@" + this.hostName;
                } else {
                    res.userName = tenantName;
                }
            }
            return res;
        },
        //处理提交
        handleSubmit(e) {
            // 登录清空面包屑里的数据
            this.clearAppKey();
            this.clearActiveKey();
            this.clearNavigation();
            this.setFrontType('user');

            e.preventDefault()
            const {
                form: { validateFields },
                state,
                Login,
            } = this;
            //登录状态为true
            state.loginBtn = true
            const validateFieldsKey = ['username', 'password', 'validCode'];
            // const validateFieldsKey = ['username', 'password'];
            validateFields(validateFieldsKey, { force: true }, (err, values) => {
                if (!err) {
                    //租户校验登录名
                    let res = this.checkUserName(values.username);
                    if (!res.status) {
                        state.loginBtn = false
                        return;
                    }

                    const loginParams = { ...values }
                    delete loginParams.username;
                    loginParams['username'] = res.userName;
                    if (this.isTenantLogin) {
                        loginParams.tenantId = this.tenantId;
                    }


                    if (this.passwordPublicKey) {
                        loginParams.password = this.getJsEncryptPassword(values.password.trim());
                    } else if ("md5" == this.passwordmode) {
                        loginParams.password = this.$md5(values.password.trim())
                    } else if ("sm2" == this.passwordmode) {
                        loginParams.password = this.sm2Encrypt(values.password.trim())
                    }
                    loginParams.deviceId = this.deviceId;
                    Login(loginParams)
                        .then((res) => this.loginSuccess(res))
                        .catch(err => this.requestFailed(err))
                        .finally(() => {
                            state.loginBtn = false
                        })

                } else {
                    setTimeout(() => {
                        state.loginBtn = false
                    }, 600)
                }
            })
        },
        //获取验证码
        async getImgCode() {
            this.deviceId = uuid.uuid(16, 32);
            await LoginApi.imgcode(this.deviceId).then(res => {
                const raw = res.data
                this.codesrc = URL.createObjectURL(raw)
            })
        },
        //登录成功处理
        loginSuccess(res) {
            if (res.code === 200) {
                document.title = JSON.parse(localStorage.getItem("siteName") || "{}")[localStorage.getItem('language') || 'zh-CN'] || "敏捷开发平台";
                //存在需要跳转的URL,则跳转到指定的URL
                if (this.redirect && this.redirect != '/') {
                    var basePath = process.env.VUE_APP_ADMIN_FRONT;
                    if (this.redirect.startWith(basePath)) {
                        this.$router.push({ path: this.redirect });
                    } else {
                        location.href = basePath + this.redirect;
                    }
                } else {
                    this.$router.push({ name: 'admin-index' }, () => {
                        this.$notification.success({
                            message: this.i18n('tips.welcome', '欢迎'),
                            description: `${timeFix()}，` + this.i18n('tips.welcomeBack', '欢迎回来!')
                        })
                    })
                }
                this.isLoginError = false
            } else {
                this.requestFailed(res)
            }
        },
        //二维码登录
        qrcodeLogin(loginType) {
            this.$router.push({ name: 'qrcodeLogin', params: { loginType: loginType, tenantId: this.tenantId, hostName: this.hostName } });
        },
        //登录失败处理
        requestFailed(err) {
            this.isLoginError = true
            this.getImgCode()
        },
        getFilePath(fileId) {
            return "/api/api-system/system/core/sysFile/public/download/" + fileId;
        }

    }
}
</script>

<style lang="less" scoped>
.login-language-common {
    min-width: 140px;
    background: #FFFFFF;
    box-shadow: 0px 0px 10px 1px rgba(0, 0, 0, 0.08);
    border-radius: 4px 4px 4px 4px;
    position: absolute;
    top: 30px;
    right: 0px;
    padding: 10px 0px;
    z-index: 9999;
}

.login-language-common-list {
    height: 32px;
    align-items: center;
    display: flex;
    cursor: pointer;
    padding: 0px 5px;
    margin: 0px 5px;
    border-right: 2px;

    i {
        color: #1890FF;
        font-size: 18px;
    }
}

.login-language-common-list:hover {
    background: rgba(24, 144, 255, 0.1);
}

.login-language-common-list-le {
    flex: 1;
    font-weight: 400;
    color: #29304C;
    font-size: 14px;
}

.login-language {
    position: absolute;
    top: 30px;
    right: 30px;
}

.login-language-head {
    display: flex;
    align-items: center;
    cursor: pointer;
    height: 30px;
    color: #666666;
    font-size: 14px;
}

.otherLogin {
    text-align: center;
    padding: 4px 0;
    margin-top: 18px;
    position: relative;
}

.otherLogin:after,
.otherLogin:before {
    content: '';
    position: absolute;
    top: 50%;
    margin-top: 1px;
    width: 38%;
    height: 1px;
}

.otherLogin:after {
    left: 0;
    background: linear-gradient(270deg, #D9D9D9 0%, #FFFFFF 100%);
}

.otherLogin:before {
    right: 1px;
    background: linear-gradient(90deg, #D9D9D9 0%, #FFFFFF 100%);
}

.footerIconBox {
    text-align: center;
    font-size: 0;
}

.iconItem {
    display: inline-block;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    margin: 16px 20px 0;
}

.feishu {
    background: url("~@/image/loginIcon/fs.png") no-repeat;
}

.WeChat {
    background: url("~@/image/loginIcon/qywx.png") no-repeat;
}

.WeChatGzh {
    border: 1px solid rgb(234, 234, 234);
    background: url("~@/image/loginIcon/gzh.png") no-repeat center center;
}

.dingding {
    background: url("~@/image/loginIcon/dd.png") no-repeat;
}

.wxspan {
    margin-top: 5px;
    line-height: 14px;
    padding-right: 10px;
}

.bblict {
    display: inline-block;
    width: 25px;
    height: 25px;
    border-radius: 50%;
}


.main {
    padding: 20px 40px;
    overflow: hidden;
    width: 440px !important;
    background-color: #ffffff;
    box-shadow: 0px 0px 49px 0px rgba(7, 63, 126, 0.24);
    border-radius: 16px;
}

.hermg {
    width: 54px;
    margin: auto;
    margin-top: 24px;

    img {
        width: 54px;
    }
}

.jpaas {
    margin-top: 10px;
    font-size: 20px;
    color: #29304C;
    font-weight: bold;
}

.jpaasbutton {
    overflow: hidden;
    margin: auto;
    margin-top: 16px;
    padding-bottom: 30px;
}

.imgwing img {
    width: 100%;
    height: 40px;
}

.ant-tabs-nav-wrap {
    border-bottom: 1px solid #eeeeee !important;
    // borderBottom: 'unset'
}

.user-layout-login {
    label {
        font-size: 14px;
    }

    .getCaptcha {
        display: block;
        width: 100%;
        height: 40px;
    }

    .forge-password {
        font-size: 14px;
    }

    button.login-button {
        padding: 0 10px;
        font-size: 16px;
        height: 40px;
        width: 100%;
    }

    .user-login-other {
        text-align: left;
        margin-top: 24px;
        line-height: 22px;

        .item-icon {
            font-size: 24px;
            color: rgba(0, 0, 0, 0.2);
            margin-left: 16px;
            vertical-align: middle;
            cursor: pointer;
            transition: color 0.3s;

            &:hover {
                color: #1890ff;
            }
        }

        .register {
            float: right;
        }
    }
}
</style>
